<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>页面置灰</title>
    <style>
        .button-group {
            display: flex;
            margin-bottom: 20px;
        }

        .button-group button {
            margin-right: 10px;
            cursor: pointer;
        }

        #box {
            width: 200px;
            height: 200px;
            margin-bottom: 10px;
        }

        .red {
            background-color: red;
        }

        html {
            position: relative;
            width: 100%;
            height: 100%;
        }

        /* 给html遮罩层 */
        .mask::before {
            content: '';
            /* position: fixed; 首屏置灰 */
            position: absolute;
            /* 部分置灰 */
            backdrop-filter: grayscale(1);
            pointer-events: none;
            inset: 0;
            z-index: 100;
        }

        .not-gray {
            position: relative;
            z-index: 10000;
        }

        .gray {
            filter: grayscale(100%);
            -webkit-filter: grayscale(100%);
        }
    </style>
</head>

<body>
    <div class="button-group">
        <button onclick="handleFullGray()">全部置灰</button>
        <button onclick="handleFirstScreenGray()">首屏置灰</button>
        <button onclick="handlePartGray()">部分置灰</button>
    </div>

    <span style="font-size: 20px; color: green">你好啊</span>
    <div id="box" class="box1 red">

    </div>
    <div id="box" class="box2 red">

    </div>
    <div id="box" class="box3 red">

    </div>
    <div id="box" class="box4 red">

    </div>
    <div id="box" class="box5 red">

    </div>
</body>
<script>
    let root = document.getElementsByTagName('html')[0]

    function handleFullGray () {
        // html直接设置样式
        // const ele = document.getElementsByTagName('html')[0]
        // ele.style.filter = 'grayscale(100%)'

        // 写入css标签
        let style = document.createElement('style')
        style.setAttribute('type', 'text/css')
        style.textContent = `
            .gray {
                filter: grayscale(100%);
                -webkit-filter: grayscale(100%);
            }
        `
        document.head.appendChild(style)

        toggleClassName(root, 'gray')
    }

    function toggleClassName (ele, name) {
        if (ele.className.indexOf(name) > -1) {
            ele.className = ele.className.replace(name, '').trim()
        } else {
            ele.className = ele.className + ' ' + name
        }
    }

    function handleFirstScreenGray () {
        toggleClassName(root, 'mask')
    }

    function handlePartGray () {
        let notGraySelector = ['.box1', '.box2']
        notGraySelector.forEach(selector => {
            let doms = [...document.querySelectorAll(selector)]
            doms.forEach(dom => {
                if (!dom) return
                dom.keepColor = true
                let parent = dom.parentNode
                while (parent && !parent.colorful) {
                    parent.colorful = true
                    parent = parent.parentNode
                }
            })
        })
        walk(document.body)

        function walk (node) {
            // nodeType 1 元素节点 2 属性节点 3 文本节点
            if (node.nodeType !== 1) return
            if (node.keepColor) return
            if (!node.colorful) {
                toggleClassName(node, 'gray')
                return
            }

            for (let i = 0; i < node.children.length; i++) {
                let child = node.children[i]
                walk(child)
            }
        }
    }
</script>

</html>